#include<vector>
#include<pthread.h>
#include<semaphore.h>

const static int defaultNum = 5;

template<class T>
class RingQueue
{
private:
    void P(sem_t &sem)
    {
        sem_wait(&sem);
    }
    void V(sem_t &sem)
    {
        sem_post(&sem);
    }
    void Lock(pthread_mutex_t &mutex)
    {
        pthread_mutex_lock(&mutex);
    }
    void UnLock(pthread_mutex_t &mutex)
    {
        pthread_mutex_unlock(&mutex);
    }

public:
    RingQueue(int num = defaultNum)
        :ring_queue_(num), cap_(num),  p_step_(0), c_step_(0)           //p_space_sem_与c_data_sem_在下面用对应函数初始化，而不是在此直接用数字初始化
    {
        pthread_mutex_init(&p_mutex_, nullptr);
        pthread_mutex_init(&c_mutex_, nullptr);
        sem_init(&p_space_sem_, 0, num);
        sem_init(&c_data_sem_, 0, 0);
    }

    void Push(const T& in)
    {
        P(p_space_sem_);
        Lock(p_mutex_);
        ring_queue_[p_step_] = in;
        ++p_step_;
        //p_step_ %= ring_queue_.size();
        p_step_ %= cap_;
        UnLock(p_mutex_);
        V(c_data_sem_);
    }

    void Pop(T *out)
    {
        P(c_data_sem_);
        Lock(c_mutex_);
        *out = ring_queue_[c_step_];
        ++c_step_;
        //c_step_ %= ring_queue_.size();
        c_step_ %= cap_;
        UnLock(c_mutex_);
        V(p_space_sem_);        //此处参数是p_space_sem_而不是c_data_sem_，不要写错
    }


    ~RingQueue()
    {
        pthread_mutex_destroy(&p_mutex_);
        pthread_mutex_destroy(&c_mutex_);
        sem_destroy(&p_space_sem_);
        sem_destroy(&c_data_sem_);
    }

private:
    std::vector<T> ring_queue_;
    int cap_;       //记录ring_queue_存放数据的数量，方便上方Push与Pop函数进行取模
    int p_step_;
    int c_step_;
    pthread_mutex_t p_mutex_;
    pthread_mutex_t c_mutex_;
    sem_t p_space_sem_;
    sem_t c_data_sem_;
};